package cn.initcap.concurrency.concurrency.aqs;

import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Semaphore;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;

/**
 * 用于控制单位时间内的最大并发访问量。
 *
 * @author initcap
 * @date Created in 2018/6/17 PM6:05.
 */
@Slf4j
public class SemaphoreAcquire {

    private static final int THREAD_COUNT = 20;

    private static final ExecutorService exec = new ThreadPoolExecutor(0, THREAD_COUNT, 60L,
            TimeUnit.SECONDS, new SynchronousQueue<>(),
            new ThreadFactoryBuilder().setNameFormat("SemaphoreAcquire").build());

    /**
     * 给定的值代表允许的并发数
     */
    private static final Semaphore semaphore = new Semaphore(3);

    public static void main(String[] args) throws Exception {
        for (int i = 0; i < THREAD_COUNT; i++) {
            final int threadNum = i;
            acquire(threadNum);
        }
        log.info("finish");
        exec.shutdown();
    }

    private static void acquire(int threadNum) {
        exec.execute(() -> {
            try {
                //获取一个许可
                semaphore.acquire();
                log.info("{}", threadNum);
                Thread.sleep(1000);
                //释放一个许可
                semaphore.release();
            } catch (Exception e) {
                log.error("exception", e);
            }
        });
    }

    private static void acquirePermits(int threadNum) {
        exec.execute(() -> {
            try {
                //获取多个许可
                semaphore.acquire(3);
                log.info("{}", threadNum);
                Thread.sleep(1000);
                //释放多个许可，也可以获取多个许可然后一个一个进行释放
                semaphore.release(3);
            } catch (Exception e) {
                log.error("exception", e);
            }
        });
    }

    private static void tryAcquire(int threadNum) {
        exec.execute(() -> {
            try {
                //可以拿到许可就进行操作，拿不到就丢弃
                if (semaphore.tryAcquire()) {
                    log.info("{}", threadNum);
                    Thread.sleep(1000);
                    //释放
                    semaphore.release();
                }
            } catch (Exception e) {
                log.error("exception", e);
            }
        });
    }

    private static void tryAcquireTimeout(int threadNum) {
        exec.execute(() -> {
            try {
                //指定时间内，可以拿到许可就进行操作，拿不到就丢弃
                if (semaphore.tryAcquire(5000, TimeUnit.MILLISECONDS)) {
                    log.info("{}", threadNum);
                    Thread.sleep(1000);
                    //释放
                    semaphore.release();
                }
            } catch (Exception e) {
                log.error("exception", e);
            }
        });
    }

}
